package client;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import model.Category;
import model.Discuss;
import model.DiscussInfo;
import model.DiscussMessage;
import model.DiscussUser;
import model.Font;
import model.Friend;
import model.FriendStatus;
import model.Group;
import model.GroupInfo;
import model.GroupManege;
import model.GroupMessage;
import model.GroupUser;
import model.Message;
import model.Recent;
import model.Time;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;

import DataBaseModel.DataBase;
import DataBaseModel.QQGroupManege;
import callback.MessageCallback;
import callback.MyCallBack;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sun.jna.platform.win32.Advapi32Util.Account;

import constant.ApiURL;

/**
 * Api客户端
 * 
 * @author ScienJus
 * @date 2015/12/18.
 */
public class SmartQQClient {
	RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000)
			.setConnectTimeout(5000).build();
	// 执行拉取消息的线程池
	private static final ScheduledThreadPoolExecutor POOL = new ScheduledThreadPoolExecutor(
			20);

	// 消息id，这个好像可以随便设置，所以设成全局的
	private static long MESSAGE_ID = 43690001;

	// 客户端id，固定的
	private static final long Client_ID = 53999199;

	// 保存cookie信息
	private HttpClientContext context = HttpClientContext.create();

	// 鉴权参数
	private String ptwebqq;

	private String vfwebqq;

	private long uin;

	private String psessionid;
	
	
	// 拉取消息的线程
	private ScheduledFuture pollMessageFuture;

	/**
	 * 登录
	 * 
	 * @throws IOException
	 * @throws ClientProtocolException
	 * @throws URISyntaxException
	 */
	public void login() throws ClientProtocolException, IOException,
			URISyntaxException {
		getQRCode();
		String url = verifyQRCode();
		getPtwebqq(url);
		getVfwebqq();
		getUinAndPsessionid();
	}

	// 登录流程1：获取二维码
	private void getQRCode() {
		System.out.println(Time.getStringDateLong()+" 开始获取二维码");
		// 发送请求的客户端
		CloseableHttpClient client = HttpClients.createDefault();
		String filePath = getClass().getResource("/").getPath()
				.concat("qrcode.png");
		HttpGet get = defaultHttpGet(ApiURL.GET_QR_CODE);
		get.setConfig(requestConfig);
		try (CloseableHttpResponse response = client.execute(get, context);
				FileOutputStream out = new FileOutputStream(filePath)) {
			int len;
			byte[] buffer = new byte[1024];
			while ((len = response.getEntity().getContent().read(buffer)) != -1) {
				out.write(buffer, 0, len);
			}
			out.close();
			System.out.println(Time.getStringDateLong()+" 二维码已保存在 " + filePath + " 文件中，请打开手机QQ并扫描二维码");
		} catch (IOException e) {
			System.err.println("获取二维码失败");
		}
	}

	// 登录流程2：校验二维码
	private String verifyQRCode() {
		System.out.println(Time.getStringDateLong()+" 等待扫描二维码");
		String qrsig = null;
		for (Cookie c : context.getCookieStore().getCookies()) {
			if (c.getName().equals("qrsig")) {
				qrsig = c.getValue();
				break;
			}
		}
		// 二维码扫描状态地址
		String url = "https://ssl.ptlogin2.qq.com/ptqrlogin?ptqrtoken="
				+ hash33(qrsig)
				+ "&webqq_type=10&remember_uin=1&login2qq=1&aid=501004106&"
				+ "u1=http%3A%2F%2Fw.qq.com%2Fproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&"
				+ "ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&"
				+ "action=0-0-157510&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10143&login_sig=&pt_randsalt=0";
		HttpGet get = new HttpGet(url);
		get.addHeader(
				"Referer",
				"https://ui.ptlogin2.qq.com/cgi-bin/login?"
						+ "daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&"
						+ "s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001");
		get.addHeader(
				"User-Agent",
				"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
		get.setConfig(requestConfig);
		// 发送请求的客户端
		CloseableHttpClient client = HttpClients.createDefault();

		// 阻塞直到确认二维码认证成功
		while (true) {
			sleep(1);
			try (CloseableHttpResponse response = client.execute(get, context)) {
				String responseText = getResponseText(response);
				responseText = new String(responseText.getBytes(), "UTF-8");
				if (responseText.contains("成功")) {

					for (String content : responseText.split("','")) {
						if (content.startsWith("http")) {
							return content;
						}
					}
				} else if (responseText.contains("已失效")) {
					System.out.println(Time.getStringDateLong()+" 二维码已失效，尝试重新获取二维码");
					getQRCode();
				}
			} catch (SocketTimeoutException ste) {
				System.out.println(Time.getStringDateLong()+" 连接超时，重新验证二维码");
				return verifyQRCode();
			} catch (IOException e) {
				System.err.println("校验二维码失败");
			}
		}

	}

	// 登录流程3：获取ptwebqq
	private void getPtwebqq(String url) {
		System.out.println(Time.getStringDateLong()+" 开始获取ptwebqq");
		// 发送请求的客户端
		CloseableHttpClient client = HttpClients.createDefault();
		HttpGet get = defaultHttpGet(ApiURL.GET_PTWEBQQ, url);
		get.setConfig(requestConfig);
		try {
			client.execute(get, context);
			for (Cookie cookie : context.getCookieStore().getCookies()) {
				if (cookie.getName().equals("ptwebqq")) {
					this.ptwebqq = cookie.getValue();
				}
			}
		} catch (SocketTimeoutException e1) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			getPtwebqq(url);
		} catch (ConnectException e2) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			getPtwebqq(url);
		} catch (IOException e) {
			System.err.println("获取ptwebqq失败");
		}
	}

	// 登录流程4：获取vfwebqq
	private void getVfwebqq() {
		System.out.println(Time.getStringDateLong()+" 开始获取vfwebqq");
		
		// 发送请求的客户端
		CloseableHttpClient client = HttpClients.createDefault();
		HttpGet get = defaultHttpGet(ApiURL.GET_VFWEBQQ, ptwebqq);
		try (CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			this.vfwebqq = responseJson.getJSONObject("result").getString(
					"vfwebqq");
		} catch (IOException e) {
			System.err.println(Time.getStringDateLong()+" 获取vfwebqq失败");
		}
	}

	// 登录流程5：获取uin和psessionid
	private void getUinAndPsessionid() {
		System.out.println(Time.getStringDateLong()+" 开始获取uin和psessionid");
		JSONObject r = new JSONObject();
		r.put("ptwebqq", ptwebqq);
		r.put("clientid", Client_ID);
		r.put("psessionid", "");
		r.put("status", "online");

		HttpPost post = defaultHttpPost(ApiURL.GET_UIN_AND_PSESSIONID,
				new BasicNameValuePair("r", r.toJSONString()));
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(post, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			this.psessionid = responseJson.getJSONObject("result").getString(
					"psessionid");
			this.uin = responseJson.getJSONObject("result").getLongValue("uin");
		} catch (IOException e) {
			System.err.println("获取uin和psessionid失败");
		}
	}

	/**
	 * 获取群列表
	 * 
	 * @return
	 */
	public List<Group> getGroupList() {
		System.out.println(Time.getStringDateLong()+" 开始获取群列表");
		JSONObject r = new JSONObject();
		r.put("vfwebqq", vfwebqq);
		r.put("hash", hash());
		try {
			// 发送请求的客户端
			HttpPost post = defaultHttpPost(ApiURL.GET_GROUP_LIST,
					new BasicNameValuePair("r", r.toJSONString()));
			post.setEntity(new UrlEncodedFormEntity(Arrays
					.asList(new BasicNameValuePair("r", r.toJSONString()))));
			try (CloseableHttpClient client = HttpClients.createDefault();
					CloseableHttpResponse response = client.execute(post,
							context)) {
				JSONObject responseJson = JSON
						.parseObject(getResponseText(response));
				return JSON.parseArray(responseJson.getJSONObject("result")
						.getJSONArray("gnamelist").toJSONString(), Group.class);
			} catch (IOException e) {
				System.err.println("获取群列表失败");
			}
		} catch (UnsupportedEncodingException e) {
			System.err.println("获取群列表失败");
		}
		return Collections.emptyList();
	}

	/**
	 * 拉取消息
	 * 
	 * @param callback
	 *            获取消息后的回调
	 */
	public void pollMessage(MessageCallback callback) {
		System.out.println(Time.getStringDateLong()+" 开始接收消息");
		JSONObject r = new JSONObject();
		r.put("ptwebqq", ptwebqq);
		r.put("clientid", Client_ID);
		r.put("psessionid", psessionid);
		r.put("key", "");

		HttpPost post = defaultHttpPost(ApiURL.POLL_MESSAGE,
				new BasicNameValuePair("r", r.toJSONString()));
		if (pollMessageFuture != null) {
			pollMessageFuture.cancel(false);
		}
		pollMessageFuture = POOL.scheduleWithFixedDelay(new PollMessageTask(
				post, callback), 1, 1, TimeUnit.MILLISECONDS);
	}

	/**
	 * 停止拉取消息
	 */
	public void stopPoll() {
		if (pollMessageFuture != null) {
			pollMessageFuture.cancel(false);
		}
		pollMessageFuture = null;
	}

	/**
	 * 发送群消息
	 * 
	 * @param groupId
	 * @param msg
	 */
	public void sendMessageToGroup(long groupId, String msg) {
		System.out.println(Time.getStringDateLong()+" 开始发送群消息");
		JSONObject r = new JSONObject();
		r.put("group_uin", groupId);
		r.put("content",
				JSON.toJSONString(Arrays.asList(msg,
						Arrays.asList("font", Font.DEFAULT_FONT)))); // 注意这里虽然格式是Json，但是实际是String
		r.put("face", 573);
		r.put("clientid", Client_ID);
		r.put("msg_id", MESSAGE_ID++);
		r.put("psessionid", psessionid);

		HttpPost post = defaultHttpPost(ApiURL.SEND_MESSAGE_TO_GROUP,
				new BasicNameValuePair("r", r.toJSONString()));
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(post, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("errCode")) {
				System.err.println("发送群消息成功");
			} else {
				System.err.println("发送群消息失败");
			}
		} catch (IOException e) {
			System.err.println("发送群消息失败");
		}
	}

	/**
	 * 发送讨论组消息
	 * 
	 * @param discussId
	 * @param msg
	 */
	public void sendMessageToDiscuss(long discussId, String msg) {
		System.out.println(Time.getStringDateLong()+" 开始发送群消息");
		JSONObject r = new JSONObject();
		r.put("did", discussId);
		r.put("content",
				JSON.toJSONString(Arrays.asList(msg,
						Arrays.asList("font", Font.DEFAULT_FONT)))); // 注意这里虽然格式是Json，但是实际是String
		r.put("face", 573);
		r.put("clientid", Client_ID);
		r.put("msg_id", MESSAGE_ID++);
		r.put("psessionid", psessionid);

		HttpPost post = defaultHttpPost(ApiURL.SEND_MESSAGE_TO_DISCUSS,
				new BasicNameValuePair("r", r.toJSONString()));
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(post, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("errCode")) {
				System.err.println("发送群消息成功");
			} else {
				System.err.println("发送群消息失败");
			}
		} catch (IOException e) {
			System.err.println("发送群消息失败");
		}
	}

	/**
	 * 发送消息
	 * 
	 * @param friendId
	 * @param msg
	 */
	public void sendMessageToFriend(long friendId, String msg) {
		System.out.println(Time.getStringDateLong()+" 开始发送消息");
		JSONObject r = new JSONObject();
		r.put("to", friendId);
		r.put("content",
				JSON.toJSONString(Arrays.asList(msg,
						Arrays.asList("font", Font.DEFAULT_FONT)))); // 注意这里虽然格式是Json，但是实际是String
		r.put("face", 573);
		r.put("clientid", Client_ID);
		r.put("msg_id", MESSAGE_ID++);
		r.put("psessionid", psessionid);

		// 发送请求的客户端
		HttpPost post = defaultHttpPost(ApiURL.SEND_MESSAGE_TO_FRIEND,
				new BasicNameValuePair("r", r.toJSONString()));
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(post, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("errCode")) {
				System.err.println("发送消息成功");
			} else {
				System.err.println("发送消息失败");
			}
		} catch (IOException e) {
			System.err.println("发送消息失败");
		}
	}

	public List<Discuss> getDiscussList() {
		System.out.println(Time.getStringDateLong()+" 开始获取讨论组列表");
		HttpGet get = defaultHttpGet(ApiURL.GET_DISCUSS_LIST, psessionid,
				vfwebqq);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				return JSON.parseArray(responseJson.getJSONObject("result")
						.getJSONArray("dnamelist").toJSONString(),
						Discuss.class);
			} else {
				System.err.println("获取讨论组列表失败");
			}
		} catch (IOException e) {
			System.err.println("获取讨论组列表失败");
		}
		return null;
	}

	/**
	 * 获取好友列表
	 * 
	 * @return
	 */
	public List<Category> getFriendList() {
		System.out.println(Time.getStringDateLong()+" 开始获取好友列表");
		JSONObject r = new JSONObject();
		r.put("vfwebqq", vfwebqq);
		r.put("hash", hash());

		HttpPost post = defaultHttpPost(ApiURL.GET_FRIEND_LIST,
				new BasicNameValuePair("r", r.toJSONString()));
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(post, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				JSONObject result = responseJson.getJSONObject("result");
				// 获得分组
				JSONArray categories = result.getJSONArray("categories");
				Map<Integer, Category> categoryMap = new HashMap<>();
				categoryMap.put(0, Category.defaultCategory());
				for (int i = 0; categories != null && i < categories.size(); i++) {
					Category category = categories.getObject(i, Category.class);
					categoryMap.put(category.getIndex(), category);
				}
				// 获得好友信息
				Map<Long, Friend> friendMap = new HashMap<>();
				JSONArray friends = result.getJSONArray("friends");
				for (int i = 0; friends != null && i < friends.size(); i++) {
					JSONObject item = friends.getJSONObject(i);
					Friend friend = new Friend();
					friend.setUserId(item.getLongValue("uin"));
					friendMap.put(friend.getUserId(), friend);
					categoryMap.get(item.getIntValue("categories")).addFriend(
							friend);
				}
				JSONArray marknames = result.getJSONArray("marknames");
				for (int i = 0; marknames != null && i < marknames.size(); i++) {
					JSONObject item = marknames.getJSONObject(i);
					friendMap.get(item.getLongValue("uin")).setMarkname(
							item.getString("markname"));
				}
				JSONArray info = result.getJSONArray("info");
				for (int i = 0; info != null && i < info.size(); i++) {
					JSONObject item = info.getJSONObject(i);
					friendMap.get(item.getLongValue("uin")).setNickname(
							item.getString("nick"));
				}
				JSONArray vipinfo = result.getJSONArray("vipinfo");
				for (int i = 0; vipinfo != null && i < vipinfo.size(); i++) {
					JSONObject item = vipinfo.getJSONObject(i);
					Friend friend = friendMap.get(item.getLongValue("u"));
					friend.setVip(item.getIntValue("is_vip") == 1);
					friend.setVipLevel(item.getIntValue("vip_level"));
				}
				return new ArrayList<>(categoryMap.values());
			} else {
				System.err.println("获取好友列表失败");
			}
		} catch (IOException e) {
			System.err.println("获取好友列表失败");
		}
		return null;
	}

	public Account getAccountInfo() {
		System.out.println(Time.getStringDateLong()+" 开始获取登录用户信息");
		HttpGet get = defaultHttpGet(ApiURL.GET_ACCOUNT_INFO);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				return responseJson.getObject("result", Account.class);
			} else {
				System.err.println("获取登录用户信息失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取登录用户信息失败");
		}
		return null;
	}

	public List<Recent> getRecentList() {
		System.out.println(Time.getStringDateLong()+" 开始获取最近会话列表");
		JSONObject r = new JSONObject();
		r.put("vfwebqq", vfwebqq);
		r.put("clientid", Client_ID);
		r.put("psessionid", "");

		HttpPost post = defaultHttpPost(ApiURL.GET_RECENT_LIST,
				new BasicNameValuePair("r", r.toJSONString()));
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(post, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				return JSON.parseArray(responseJson.getJSONArray("result")
						.toJSONString(), Recent.class);
			} else {
				System.err.println("获取最近会话列表失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取最近会话列表失败");
		}
		return null;
	}

	public String getFriendInfo(long id) {
		System.out.println(Time.getStringDateLong()+" 开始获取好友资料");
		HttpGet get = defaultHttpGet(ApiURL.GET_FRIEND_INFO, id, vfwebqq,psessionid);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				return responseJson.getJSONObject("result").getString("nick");
			} else {
				System.err.println("获取好友资料失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取好友资料失败");
		}
		return "";
	}

	public long getQQById(long id) {
		System.out.println(Time.getStringDateLong()+" 开始获取QQ号");

		HttpGet get = defaultHttpGet(ApiURL.GET_QQ_BY_ID, id, vfwebqq);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				return responseJson.getJSONObject("result").getLongValue(
						"account");
			} else {
				System.err.println("获取QQ号失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取QQ号失败");
		}
		return 0L;
	}

	public List<FriendStatus> getFriendStatus() {
		System.out.println(Time.getStringDateLong()+" 开始获取好友状态");
		HttpGet get = defaultHttpGet(ApiURL.GET_FRIEND_STATUS, vfwebqq,
				psessionid);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				return JSON.parseArray(responseJson.getJSONArray("result")
						.toJSONString(), FriendStatus.class);
			} else {
				System.err.println("获取好友状态失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取好友状态失败");
		}
		return null;
	}

	public GroupInfo getGroupInfo(long groupCode) {
		System.out.println(Time.getStringDateLong()+" 开始获取群资料");
		HttpGet get = defaultHttpGet(ApiURL.GET_GROUP_INFO, groupCode, vfwebqq);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				JSONObject result = responseJson.getJSONObject("result");
				GroupInfo groupInfo = result
						.getObject("ginfo", GroupInfo.class);
				// 获得群成员信息
				Map<Long, GroupUser> groupUserMap = new HashMap<>();
				JSONArray minfo = result.getJSONArray("minfo");
				for (int i = 0; minfo != null && i < minfo.size(); i++) {
					GroupUser groupUser = minfo.getObject(i, GroupUser.class);
					groupUserMap.put(groupUser.getUin(), groupUser);
					groupInfo.addUser(groupUser);
				}
				JSONArray stats = result.getJSONArray("stats");
				for (int i = 0; stats != null && i < stats.size(); i++) {
					JSONObject item = stats.getJSONObject(i);
					GroupUser groupUser = groupUserMap.get(item
							.getLongValue("uin"));
					groupUser.setClientType(item.getIntValue("client_type"));
					groupUser.setStatus(item.getIntValue("stat"));
				}
				JSONArray cards = result.getJSONArray("cards");
				for (int i = 0; cards != null && i < cards.size(); i++) {
					JSONObject item = cards.getJSONObject(i);
					groupUserMap.get(item.getLongValue("muin")).setCard(
							item.getString("card"));
				}
				JSONArray vipinfo = result.getJSONArray("vipinfo");
				for (int i = 0; vipinfo != null && i < vipinfo.size(); i++) {
					JSONObject item = vipinfo.getJSONObject(i);
					GroupUser groupUser = groupUserMap.get(item
							.getLongValue("u"));
					groupUser.setVip(item.getIntValue("is_vip") == 1);
					groupUser.setVipLevel(item.getIntValue("vip_level"));
				}
				return groupInfo;
			} else {
				System.err.println("获取群资料失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取群资料失败");
		}
		return null;
	}

	public DiscussInfo getDiscussInfo(long discussId) {
		System.out.println(Time.getStringDateLong()+" 开始获取讨论组资料");
		HttpGet get = defaultHttpGet(ApiURL.GET_DISCUSS_INFO, discussId,
				vfwebqq, psessionid);
		get.setConfig(requestConfig);
		try (CloseableHttpClient client = HttpClients.createDefault();
				CloseableHttpResponse response = client.execute(get, context)) {
			JSONObject responseJson = JSON
					.parseObject(getResponseText(response));
			if (0 == responseJson.getIntValue("retcode")) {
				JSONObject result = responseJson.getJSONObject("result");
				DiscussInfo discussInfo = result.getObject("info",
						DiscussInfo.class);
				// 获得讨论组成员信息
				Map<Long, DiscussUser> discussUserMap = new HashMap<>();
				JSONArray minfo = result.getJSONArray("mem_info");
				for (int i = 0; minfo != null && i < minfo.size(); i++) {
					DiscussUser discussUser = minfo.getObject(i,
							DiscussUser.class);
					discussUserMap.put(discussUser.getUin(), discussUser);
					discussInfo.addUser(discussUser);
				}
				JSONArray stats = result.getJSONArray("mem_status");
				for (int i = 0; stats != null && i < stats.size(); i++) {
					JSONObject item = stats.getJSONObject(i);
					DiscussUser discussUser = discussUserMap.get(item
							.getLongValue("uin"));
					discussUser.setClientType(item.getIntValue("client_type"));
					discussUser.setStatus(item.getString("status"));
				}
				return discussInfo;
			} else {
				System.err.println("获取讨论组资料失败 retcode:"
						+ responseJson.getIntValue("retcode"));
			}
		} catch (IOException e) {
			System.err.println("获取讨论组资料失败");
		}
		return null;
	}

	// hash加密方法
	private String hash() {
		return hash(uin, ptwebqq);
	}

	// 线程暂停
	private static void sleep(long seconds) {
		try {
			Thread.sleep(seconds * 1000);
		} catch (InterruptedException ignored) {
		}
	}

	// hash加密方法
	private static String hash(long x, String K) {
		int[] N = new int[4];
		for (int T = 0; T < K.length(); T++) {
			N[T % 4] ^= K.charAt(T);
		}
		String[] U = { "EC", "OK" };
		long[] V = new long[4];
		V[0] = x >> 24 & 255 ^ U[0].charAt(0);
		V[1] = x >> 16 & 255 ^ U[0].charAt(1);
		V[2] = x >> 8 & 255 ^ U[1].charAt(0);
		V[3] = x & 255 ^ U[1].charAt(1);

		long[] U1 = new long[8];

		for (int T = 0; T < 8; T++) {
			U1[T] = T % 2 == 0 ? N[T >> 1] : V[T >> 1];
		}

		String[] N1 = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
				"B", "C", "D", "E", "F" };
		String V1 = "";
		for (long aU1 : U1) {
			V1 += N1[(int) ((aU1 >> 4) & 15)];
			V1 += N1[(int) (aU1 & 15)];
		}
		return V1;
	}

	// 得到返回的数据
	public static String getResponseText(CloseableHttpResponse response) {
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(
				response.getEntity().getContent()))) {
			StringBuilder buffer = new StringBuilder();
			String line;
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			return buffer.toString();
		} catch (IOException e) {
			System.err.println("获取返回数据失败");
		}
		return "";
	}

	// 默认的http get
	private static HttpGet defaultHttpGet(ApiURL apiUrl, Object... params) {
		String url = apiUrl.buildUrl(params);
		HttpGet get = new HttpGet(url);
		if (apiUrl.getReferer() != null) {
			get.setHeader("Referer", apiUrl.getReferer());
		}
		get.setHeader("User-Agent", ApiURL.USER_AGENT);
		return get;
	}

	// 默认的http post
	private static HttpPost defaultHttpPost(ApiURL apiUrl,
			BasicNameValuePair... params) {
		HttpPost post = new HttpPost(apiUrl.getUrl());
		if (apiUrl.getReferer() != null) {
			post.setHeader("Referer", apiUrl.getReferer());
		}
		post.setEntity(new UrlEncodedFormEntity(Arrays.asList(params), Charset
				.forName("UTF-8")));
		post.setHeader("Origin", apiUrl.getOrigin());
		post.setHeader("User-Agent", ApiURL.USER_AGENT);
		return post;
	}

	// 拉取消息的线程
	private class PollMessageTask implements Runnable {

		// 请求的post方法
		private HttpPost post;

		// 拉取到消息的回调
		private MessageCallback callback;

		public PollMessageTask(HttpPost post, MessageCallback callback) {
			this.post = post;
			this.callback = callback;
		}

		@Override
		public void run() {
			try (CloseableHttpClient client = HttpClients.createDefault();
					CloseableHttpResponse response = client.execute(post,
							context)) {
				JSONObject responseJson = JSON
						.parseObject(getResponseText(response));

				if (responseJson.getIntValue("retcode") == 0) {
					JSONArray array = responseJson.getJSONArray("result");
					for (int i = 0; array != null && i < array.size(); i++) {
						JSONObject message = array.getJSONObject(i);
						String type = message.getString("poll_type");
						if ("message".equals(type)) {
							callback.onMessage(
									new Message(message.getJSONObject("value")),
									SmartQQClient.this);
						} else if ("group_message".equals(type)) {
							callback.onGroupMessage(
									new GroupMessage(message
											.getJSONObject("value")),
									SmartQQClient.this);
						} else if ("discu_message".equals(type)) {
							callback.onDiscussMessage(new DiscussMessage(
									message.getJSONObject("value")),
									SmartQQClient.this);
						}
					}
				} else {
					System.err.println("接受消息失败 retcode: "
							+ responseJson.getIntValue("retcode"));
				}
			} catch (IOException e) {
				System.err.println("暂时没有消息");
			} catch (Throwable te) {
				System.err.println("未知错误");
				System.out.println(te.toString());
				System.out.println("--------------------");
				System.out.println(te.getMessage());
				System.out.println("--------------------");
				te.printStackTrace();
				pollMessage(new MyCallBack());
			}
		}
	}

	/* 给群成员设置等级 */
	public static void setLevel(SmartQQClient client) throws SQLException,
			ParseException {
		List<Group> ls = client.getGroupList();// 获取群列表
		for (Group g : ls) {
			long gid = client.getQQById(g.getCode());
			GroupInfo gi = client.getGroupInfo(g.getCode());
			List<GroupUser> users = gi.getUsers();
			for (GroupUser gu : users) {
				long uid = client.getQQById(gu.getUin());
				Connection con = DataBase.getConn();
				String sql = "select * from QQGroup where gid='" + gid
						+ "' and uid='" + uid + "'";
				PreparedStatement sta1 = con.prepareStatement(sql);
				ResultSet rs = sta1.executeQuery(sql);
				if (!rs.next()) {
					SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
					Date nowTime = df.parse("1997-01-26");
					GroupManege gm = new GroupManege(String.valueOf(gid),
							String.valueOf(uid), 0, new java.sql.Date(
									nowTime.getTime()), 0);
					QQGroupManege.insertList(gm);
				}
			}
		}

	}

	/*
	 * 签到
	 */
	public  void signIn(SmartQQClient client, GroupMessage gm)
			throws SQLException, ParseException {
		long gid = client.getQQById(gm.getGroupId());
		long uid = client.getQQById(gm.getUserId());
		int[] reCode = QQGroupManege.signIn(String.valueOf(gid),
				String.valueOf(uid));
		if (reCode[0] == -2) {
			client.sendMessageToGroup(gm.getGroupId(), "亲爱的"+uid+"用户,你今天已经签过到啦!\n现在分数为："
					+ reCode[1] + "分，等级为：" + GroupManege.getLevel(reCode[1]));
			System.out.println(Time.getStringDateLong()+" 重复签到，签到失败！");
		} else if (reCode[0] == -1) {
			client.sendMessageToGroup(gm.getGroupId(), "亲爱的"+uid+"用户,抱歉，签到失败啦!\n现在分数为："
					+ reCode[1] + "分，等级为：" + GroupManege.getLevel(reCode[1]));
			System.out.println(Time.getStringDateLong()+" 签到失败！");
		} else {
			StringBuilder sb = new StringBuilder();
			sb.append("亲爱的"+uid+"用户,签到成功啦！\n");
			if (reCode[0] > 1) {
				int reward = reCode[0] * 5 > 30 ? 30 : reCode[0] * 5;
				sb.append("连续签到" + reCode[0] + "天，奖励" + reward + "分\n");
			}
			sb.append("现在分数为：" + reCode[1] + "分，等级为："
					+ GroupManege.getLevel(reCode[1]));
			client.sendMessageToGroup(gm.getGroupId(), sb.toString());
			System.out.println(Time.getStringDateLong()+" 签到成功！");
		}
	}

	/*
	 * 查询
	 */
	public  void searchLevel(SmartQQClient client, GroupMessage gm)
			throws SQLException, ParseException {
		long gid = client.getQQById(gm.getGroupId());
		long uid = client.getQQById(gm.getUserId());
		
		int score = QQGroupManege.searchScore(String.valueOf(gid),
				String.valueOf(uid));
		client.sendMessageToGroup(gm.getGroupId(), "亲爱的"+uid+"用户,查询等级成功啦!\n现在分数为：" + score
				+ "分，等级为：" + GroupManege.getLevel(score));
		System.out.println(Time.getStringDateLong()+" 查询成功！");
	}

	// 定时发送消息的线程
	/*
	 * private class TimeMessage implements Runnable {
	 * 
	 * @Override public void run() { // TODO Auto-generated method stub
	 * 
	 * }
	 * 
	 * }
	 */

	// 点歌的方法
	public static JSONObject getSong(String song)
			throws ClientProtocolException, IOException {
		CloseableHttpClient client = HttpClients.createDefault();
		HttpGet get = new HttpGet(
				"http://www.unique-liu.com/mp3/new/api.php?mp3name=" + song);
		CloseableHttpResponse response = client.execute(get);
		JSONObject responseJson = JSON.parseObject(getResponseText(response));
		return responseJson;
	}
	
	


	// hash33算法,用于扫描二维码时获取ptrtoken参数
	public static String hash33(String t) {
		int e = 0;
		for (int i = 0, n = t.length(); n > i; ++i) {
			e += (e << 5) + t.charAt(i);

		}
		return String.valueOf(2147483647 & e);
	}
	
	/*群发消息方法
	 * @param s 发送的消息
	 * @param type 发送对象类型 0全部 1好友 2群 3讨论组 
	 */
	public void sendToAll(String s,int type){
		//向所有好友群发消息
		if(type==0||type==1){
			List<Category> cl=getFriendList();
			for(Category c:cl){
				List<Friend> fl=c.getFriends();
				for(Friend f:fl){
					sendMessageToFriend(f.getUserId(), s);
				}
			}
		}
		//向所有群群发消息
		if(type==0||type==2){
			List<Group> gl=getGroupList();
			for(Group g:gl){
				sendMessageToGroup(g.getCode(), s);
			}
		}
		//向所有讨论组群发消息
		if(type==0||type==3){
			List<Discuss> dl=getDiscussList();
			for(Discuss d:dl){
				sendMessageToDiscuss(d.getId(), s);
			}
		}
	}
}